package com.imut.lagain.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.imut.lagain.exception.WechatException;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;

/**
 * 微信工具类
 */
public class WechatUtil {
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WechatUtil.class);

    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 验证微信服务器签名
     *
     * @param signature 微信加密签名
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param token     开发者token
     * @return 验证结果
     */
    public static boolean verifySignature(String signature, String timestamp, String nonce, String token) {
        if (!StringUtils.hasText(signature) || !StringUtils.hasText(timestamp) ||
                !StringUtils.hasText(nonce) || !StringUtils.hasText(token)) {
            return false;
        }

        try {
            log.info("1. 将token、timestamp、nonce三个参数进行字典序排序");
            String[] array = {token, timestamp, nonce};
            Arrays.sort(array);

            log.info("2. 将三个参数字符串拼接成一个字符串进行sha1加密");
            StringBuilder sb = new StringBuilder();
            for (String str : array) {
                sb.append(str);
            }

            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(sb.toString().getBytes());

            StringBuilder hexStr = new StringBuilder();
            String shaHex;
            for (byte b : digest) {
                shaHex = Integer.toHexString(b & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }

            log.info("3. 将sha1加密后的字符串可与signature对比");
            return hexStr.toString().equals(signature);
        } catch (Exception e) {
            log.error("验证微信签名失败", e);
            return false;
        }
    }

    /**
     * 解析微信XML消息
     *
     * @param xmlData XML数据
     * @return 解析结果
     */
    public static Map<String, String> parseXmlMessage(String xmlData) {
        Map<String, String> result = new HashMap<>();
        if (!StringUtils.hasText(xmlData)) {
            return result;
        }

        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new ByteArrayInputStream(xmlData.getBytes(StandardCharsets.UTF_8)));

            Element root = doc.getDocumentElement();
            NodeList nodeList = root.getChildNodes();

            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    result.put(node.getNodeName(), node.getTextContent());
                }
            }
        } catch (Exception e) {
            log.error("解析微信XML消息失败", e);
        }

        return result;
    }

    /**
     * 解析微信XML消息（别名方法，用于兼容旧代码）
     *
     * @param xmlData XML数据
     * @return 解析结果
     */
    public static Map<String, String> parseXml(String xmlData) {
        return parseXmlMessage(xmlData);
    }

    /**
     * 构建微信XML响应消息
     *
     * @param toUser   接收方openid
     * @param fromUser 发送方微信号
     * @param msgType  消息类型
     * @param content  消息内容
     * @return XML字符串
     */
    public static String buildXmlResponse(String toUser, String fromUser, String msgType, String content) {
        long createTime = System.currentTimeMillis() / 1000;
        StringBuilder xml = new StringBuilder();
        xml.append("<xml>");
        xml.append("<ToUserName><![CDATA[").append(toUser).append("]]></ToUserName>");
        xml.append("<FromUserName><![CDATA[").append(fromUser).append("]]></FromUserName>");
        xml.append("<CreateTime>").append(createTime).append("</CreateTime>");
        xml.append("<MsgType><![CDATA[").append(msgType).append("]]></MsgType>");
        xml.append("<Content><![CDATA[").append(content).append("]]></Content>");
        xml.append("</xml>");
        return xml.toString();
    }

    /**
     * 构建文本消息响应
     *
     * @param toUser   接收方OpenID
     * @param fromUser 开发者微信号
     * @param content  回复内容
     * @return XML格式的响应消息
     */
    public static String buildTextResponse(String toUser, String fromUser, String content) {
        StringBuilder xml = new StringBuilder();
        xml.append("<xml>");
        xml.append("<ToUserName><![CDATA[").append(toUser).append("]]></ToUserName>");
        xml.append("<FromUserName><![CDATA[").append(fromUser).append("]]></FromUserName>");
        xml.append("<CreateTime>").append(System.currentTimeMillis() / 1000).append("</CreateTime>");
        xml.append("<MsgType><![CDATA[text]]></MsgType>");
        xml.append("<Content><![CDATA[").append(content).append("]]></Content>");
        xml.append("</xml>");
        return xml.toString();
    }

    /**
     * 构建模板消息数据
     *
     * @param data 原始数据
     * @return 模板数据
     */
    public static Map<String, Object> buildTemplateData(Map<String, Object> data) {
        Map<String, Object> templateData = new HashMap<>();
        if (data != null) {
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                Map<String, Object> valueMap = new HashMap<>();
                valueMap.put("value", entry.getValue());
                templateData.put(entry.getKey(), valueMap);
            }
        }
        return templateData;
    }

    /**
     * 检查微信API响应
     *
     * @param response 响应数据
     * @throws WechatException 微信异常
     */
    public static void checkWechatApiResponse(Map<String, Object> response) throws WechatException {
        if (response == null) {
            throw new WechatException("微信API响应为空");
        }

        Object errcode = response.get("errcode");
        if (errcode != null && !"0".equals(errcode.toString())) {
            String errmsg = (String) response.get("errmsg");
            throw new WechatException("微信API调用失败: " + errcode + " - " + errmsg);
        }
    }

    /**
     * 生成随机字符串
     *
     * @param length 长度
     * @return 随机字符串
     */
    public static String generateRandomString(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));
        }
        return sb.toString();
    }

    /**
     * 获取当前时间戳
     *
     * @return 时间戳
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 验证OpenID格式
     *
     * @param openId OpenID
     * @return 验证结果
     */
    public static boolean isValidOpenId(String openId) {
        return StringUtils.hasText(openId) && openId.length() == 28;
    }

    /**
     * 验证MediaID格式
     *
     * @param mediaId MediaID
     * @return 验证结果
     */
    public static boolean isValidMediaId(String mediaId) {
        return StringUtils.hasText(mediaId) && mediaId.length() > 0;
    }

    /**
     * 格式化微信错误信息
     *
     * @param errorCode 错误码
     * @param errorMsg  错误信息
     * @return 格式化后的错误信息
     */
    public static String formatWechatError(String errorCode, String errorMsg) {
        return String.format("微信错误[%s]: %s", errorCode, errorMsg);
    }

    /**
     * 将对象转换为JSON字符串
     *
     * @param obj 对象
     * @return JSON字符串
     */
    public static String toJsonString(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            log.error("对象转JSON失败", e);
            return "{}";
        }
    }

    /**
     * 将JSON字符串转换为Map
     *
     * @param jsonString JSON字符串
     * @return Map对象
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> fromJsonString(String jsonString) {
        try {
            return objectMapper.readValue(jsonString, Map.class);
        } catch (Exception e) {
            log.error("JSON转Map失败", e);
            return new HashMap<>();
        }
    }
}